/*
 * Created on 2005-1-7
 *
 */
package com.taobao.common.dao.persistence;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.StringTokenizer;

import org.springframework.core.io.Resource;

import com.taobao.common.dao.persistence.exception.DBRouterException;

/**
 * ��ݿ�ֿ�Ĳ�����Ѱ���������ļ�������
 *
 * @author xingdian
 * @version $Id: DBRouteConfig.java,v 1.1 2005/05/13 08:11:21 xingdian Exp $
 */
public class DBRouteConfig {
  private Resource configLocation;
  private List     routingRules        = new ArrayList();
  private List     allNodeNameList     = new ArrayList();
  private List     defaultNodeNameList = new ArrayList();
  private Map      statementRuleMap    = new HashMap();
  private Map      dbRuleMap           = new HashMap();

  /**
   * ���·�ɲ��Է��ظ�·��ָ������ݿ� ֱ�Ӹ�ݿͻ���ָ����DBRoute����Ӧ�ñ���ѯ����ݿ�
   *
   * @param DBRoute
   *
   * @return List
   *
   * @throws DBRouterException
   */
  public List routingDB(DBRoute dbRoute) throws DBRouterException {
    if (null == dbRoute) {
      return null;
    }

    List nodeNameList = new ArrayList();

    if (dbRoute.getRoutingStrategy() == DBRoute.BY_XID) {
      String xid = dbRoute.getXid();

      if (xid != null) {
        if (xid.indexOf(",") != -1) {
          StringTokenizer st = new StringTokenizer(xid, ",");

          while (st.hasMoreTokens()) {
            String dbxid = st.nextToken();

            if (allNodeNameList.contains(dbxid)) {
              nodeNameList.add(dbxid);
            }
          }

          return nodeNameList;
        } else if (allNodeNameList.contains(xid)) {
          nodeNameList.add(xid);
          return nodeNameList;
        }
      }
    }

    if (dbRoute.getRoutingStrategy() == DBRoute.BY_USER) {
      String userId = dbRoute.getUserId();

      if (userId != null) {
        Iterator it = routingRules.iterator();

        while (it.hasNext()) {
          DBRouteRule rr = (DBRouteRule) it.next();

          if (rr.getRuleBaseName().equals("UserId")) {
            if (rr.isMatched(userId)) {
              nodeNameList.add(rr.getdbName());
              return nodeNameList;
            }
          }
        }
      }
    }

    return null;
  }

  /**
   * ��ݲ�ѯ��SQLMAPING ID ���������ĸ���ݿ�
   *
   * @param statement
   *
   * @return
   *
   * @throws DBRouterException
   */
  public List routingDB(String statement) throws DBRouterException {
    if (statement == null) {
      return null;
    }

    String xid = (String) statementRuleMap.get(statement);

    if (xid != null) {
      List nodeNameList = new ArrayList();

      if (xid.indexOf(",") != -1) {
        StringTokenizer st = new StringTokenizer(xid, ",");

        while (st.hasMoreTokens()) {
          String dbxid = st.nextToken();

          if (allNodeNameList.contains(dbxid)) {
            nodeNameList.add(dbxid);
          }
        }

        return nodeNameList;
      } else if (allNodeNameList.contains(xid)) {
        nodeNameList.add(xid);
        return nodeNameList;
      }
    }

    return null;
  }

  /**
   * ������ݿ�·�ɵ�����ڣ�һ��ͻ��˾���ô˷�������Ӧ�ò�ѯ����ݿ⡣
   *
   * @param dbRoute
   * @param statement
   *
   * @return
   *
   * @throws DBRouterException
   */
  public List routingDB(DBRoute dbRoute, String statement) throws DBRouterException {
    List nodeNameListByNodeRule = routingDB(dbRoute);

    if ((nodeNameListByNodeRule != null) && !nodeNameListByNodeRule.isEmpty()) {
      return nodeNameListByNodeRule;
    }

    List nodeNameListByStatementRule = routingDB(statement);

    if (nodeNameListByStatementRule != null) {
      return nodeNameListByStatementRule;
    }

    return defaultNodeNameList;
  }

  /**
   * ��ʼ���������˴���������г�ʼ��
   *
   * @throws DBRouterException
   */
  public void init() throws DBRouterException {
    // ��ʼ�������ļ���ָ���Ĺ��򼯺�
    if (dbRuleMap.size() == 0) {
      return;
    }

    String dbKey;
    String ruleKey;
    String rule;

    for (Iterator it = dbRuleMap.keySet().iterator(); it.hasNext();) {
      dbKey = (String) it.next();

      Properties element = (Properties) dbRuleMap.get(dbKey);

      for (Iterator iter = element.entrySet().iterator(); iter.hasNext();) {
        Map.Entry entry = (Entry) iter.next();

        ruleKey = (String) entry.getKey();
        rule = (String) entry.getValue();

        DBRouteRule dbRule = new DBRouteRule(dbKey, ruleKey, rule);

        routingRules.add(dbRule);
      }
    }

    try {
      // ��ʼ��SQL���ӳ�伯��
      statementRuleMap = DBRouteConfigBuilder.buildRouteMap(configLocation.getInputStream());
    } catch (DBRouterException e) {
      throw new DBRouterException("StatementRuleMap config file parse error.", e);
    } catch (IOException e) {
      throw new DBRouterException("StatementRuleMap config file read error.", e);
    }
  }

  /**
   * @return Returns the allNodeNameList.
   */
  public List getAllNodeNameList() {
    return allNodeNameList;
  }

  /**
   * @param allNodeNameList
   *          The allNodeNameList to set.
   */
  public void setAllNodeNameList(List allNodeNameList) {
    this.allNodeNameList = allNodeNameList;
  }

  /**
   * @return Returns the defaultNodeNameList.
   */
  public List getDefaultNodeNameList() {
    return defaultNodeNameList;
  }

  /**
   * @param defaultNodeNameList
   *          The defaultNodeNameList to set.
   */
  public void setDefaultNodeNameList(List defaultNodeNameList) {
    this.defaultNodeNameList = defaultNodeNameList;
  }

  /**
   * @return Returns the dbRuleMap.
   */
  public Map getDbRuleMap() {
    return dbRuleMap;
  }

  /**
   * @param dbRuleMap
   *          The dbRuleMap to set.
   */
  public void setDbRuleMap(Map dbRuleMap) {
    this.dbRuleMap = dbRuleMap;
  }

  /**
   * @param configLocation
   *          The configLocation to set.
   */
  public void setConfigLocation(Resource configLocation) {
    this.configLocation = configLocation;
  }
}
